package com.aispeech.asr.comm.utils;

import javax.net.ssl.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;

public class HttpUtils {
    private static final String GET = "GET";
    private static final String POST = "POST";
    private static final SSLSocketFactory SSL_SOCKET_FACTORY = initSSLSocketFactory();
    private static final TrustAnyHostnameVerifier TRUST_ANY_HOSTNAME_VERIFIER = new TrustAnyHostnameVerifier();
    private static String CHARSET = "UTF-8";

    public static String get(String url) {
        HttpURLConnection connection = null;
        try {
            connection = getHttpConnection(url, GET, null, null);
            connection.connect();
            return getResponse(connection);

        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (connection != null)
                connection.disconnect();
        }
    }

    private static String getResponse(HttpURLConnection connection) {
        BufferedReader reader = null;

        try {
            reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), CHARSET));
            String line = reader.readLine();
            if (line == null) return "";

            StringBuilder builder = new StringBuilder();
            builder.append(line);

            while ((line = reader.readLine()) != null)
                builder.append('\n').append(line);

            return builder.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException ioex) {
                    System.err.println(ioex);
                }
            }
        }
    }

    private static HttpURLConnection getHttpConnection(String url, String method,
                                                       Map<String, String> queryParams,
                                                       Map<String, String> headers) throws IOException {
        StringBuilder stringBuilder = new StringBuilder(url);

        if (queryParams != null && !queryParams.isEmpty()) {
            boolean isFirst = (url.indexOf(63) == -1);
            if (isFirst)
                stringBuilder.append("?");

            for (Map.Entry<String, String> entry : queryParams.entrySet()) {
                stringBuilder
                        .append(entry.getKey())
                        .append('=')
                        .append(URLEncoder.encode(entry.getValue(), CHARSET))
                        .append('&');

            }
        }

        HttpURLConnection connection = (HttpURLConnection) new URL(stringBuilder.toString()).openConnection();

        if (connection instanceof HttpsURLConnection) {
            ((HttpsURLConnection) connection).setSSLSocketFactory(SSL_SOCKET_FACTORY);
            ((HttpsURLConnection) connection).setHostnameVerifier(TRUST_ANY_HOSTNAME_VERIFIER);
        }

        connection.setRequestMethod(method);
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setConnectTimeout(19000);
        connection.setReadTimeout(19000);
        connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        connection.setRequestProperty("User-Agent", "com.aispeech.task.HttpUtils");

        if (headers != null) {
            headers.forEach((key, value) -> connection.setRequestProperty(key, value));
        }

        return connection;
    }

    private static SSLSocketFactory initSSLSocketFactory() {
        try {
            TrustManager[] trustManagers = new TrustManager[]{new TrustAnyTrustManager()};
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, trustManagers, new SecureRandom());
            return context.getSocketFactory();
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            throw new RuntimeException(e);
        }
    }

    private static class TrustAnyTrustManager implements X509TrustManager {
        private TrustAnyTrustManager() {
        }

        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }
    }

    private static class TrustAnyHostnameVerifier implements HostnameVerifier {
        private TrustAnyHostnameVerifier() {
        }

        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }
}
